#ifndef WORLD_CAMERA_H
#define WORLD_CAMERA_H

#include "scrolling.h"
#include "helper_functions.h"
#include "sprite_handler.h"
#include "characters/characters.h"

int getCameraX();
int getCameraY();
int getCameraRight();
int getCameraBottom();

// Translation functions
int screenToWorldX( unsigned char const value );
unsigned char worldToScreenX( int const value );
int screenToWorldY( unsigned char const value );
unsigned char worldToScreenY( int const value );

BOOL getMapCoordinates( SpriteHandler const * sprite, int * x, int * y );

BOOL isPointOnScreen( int const x, int const y );

// Returns true if sprite is visible on the screen
BOOL isVisible( SpriteHandler const * sprite );

// Removes sprites that shouldn't be visible from the screen
// by checking their world coordinates
void cullForInvisible();

// This function will move all the sprite handlers that are visible on the screen
// to give the illusion that the camera is moving away from them
// void moveWorld( int relative_x, int relative_y );

// Implementation

int getCameraX()
{
	return starsBG.x;
}

int getCameraY()
{
	return starsBG.y;
}

int getCameraRight()
{
	return starsBG.x + SCREEN_WIDTH;
}

int getCameraBottom()
{
	return starsBG.y + SCREEN_HEIGHT;
}

int screenToWorldX( unsigned char const value )
{
	return value + getCameraX();
}

unsigned char worldToScreenX( int const value )
{
	return (unsigned char)(value - getCameraX());
}

int screenToWorldY( unsigned char const value )
{
	return value + getCameraY();
}

unsigned char worldToScreenY( int const value )
{
	return (unsigned char)(value - getCameraY());
}

BOOL isPointOnScreen( int const x, int const y )
{
	int camera_left = getCameraX();
	int camera_right = getCameraRight();
	int camera_top = getCameraY();
	int camera_bottom = getCameraBottom();
	
	return ( camera_left < x && x < camera_right &&
			 camera_top < y && y < camera_bottom );
}

BOOL isVisible( SpriteHandler const * sprite )
{
	int sprite_left = -1;
	int sprite_right = -1;
	int sprite_top = -1;
	int sprite_bottom = -1;
	
	// get the map coordinates of the sprite
	// place in the above varriables
	switch ( sprite->characterType )
	{
		case CHAR_NONE:
		{
			break;
		}
		case CHAR_PLAYER:
		{
			PlayerData const * udata = (PlayerData const*) sprite->userData;
			
			sprite_left = udata->map_position_x;
			sprite_top = udata->map_position_y;
			sprite_right = sprite_left + GetSpriteWidth( sprite );
			sprite_bottom = sprite_top + GetSpriteHeight( sprite );
			
			break;
		}
		case CHAR_HEALTH:
		{
			break;
		}
		case CHAR_UPGARDE:
		{
			break;
		}
		case CHAR_ENEMY1:
		{
			break;
		}
		case CHAR_ENEMY2:
		{
			break;
		}
		case CHAR_ENEMY_TURRENT:
		{
			TurretData const * udata = (TurretData const*) sprite->userData;
			
			sprite_left = udata->map_position_x;
			sprite_top = udata->map_position_y;
			sprite_right = sprite_left + GetSpriteWidth( sprite );
			sprite_bottom = sprite_top + GetSpriteHeight( sprite );
			break;
		}
		case CHAR_ENEMY:
		{
            EnemyData const * udata = (EnemyData const*) sprite->userData;
			
			sprite_left = udata->map_position_x;
			sprite_top = udata->map_position_y;
			sprite_right = sprite_left + GetSpriteWidth( sprite );
			sprite_bottom = sprite_top + GetSpriteHeight( sprite );
			
			break;
        }
		case CHAR_ENEMY_BOSS:
		{
			break;
		}
		case CHAR_LASER:
		{
			LaserData const * udata = (LaserData const*) sprite->userData;
			
			sprite_left = udata->map_position_x;
			sprite_top = udata->map_position_y;
			sprite_right = sprite_left + GetSpriteWidth( sprite );
			sprite_bottom = sprite_top + GetSpriteHeight( sprite );
			break;
		}
		case CHAR_EXPLOSION:
		{
			ExplosionData const * udata = (ExplosionData const*) sprite->userData;
			
			sprite_left = udata->map_position_x;
			sprite_top = udata->map_position_y;
			sprite_right = sprite_left + GetSpriteWidth( sprite );
			sprite_bottom = sprite_top + GetSpriteHeight( sprite );
			break;
		}
		default:
		{
			break;
		}
	}

	// Error check, if any values were not set, then gtfo
	if ( sprite_left == -1	||
		 sprite_right == -1	||
		 sprite_top == -1	||
		 sprite_bottom == -1 )
	{
		return true;
	}
	
	// Check if any of those four coordinates exist on the screen
	if ( isPointOnScreen( sprite_left, sprite_top ) || 
		 isPointOnScreen( sprite_left, sprite_bottom ) ||
		 isPointOnScreen( sprite_right, sprite_top ) ||
		 isPointOnScreen( sprite_right, sprite_bottom ) )
	{
		return true;
	}
	
	return false;
}

void cullForInvisible()
{
	// foreach sprite
	int i;
	for ( i = 0 ; i < MAX_SPRITE_HANDLERS ; ++i )
	{			
		SpriteHandler * sprite = &g_spriteHandlers[ i ];
		
		// check if sprite is alive and on screen
		if ( sprite->alive && isVisible( sprite ) )
		{
			// if so, who cares?
			// maybe move to proper screen position?
			int x, y;
			
			getMapCoordinates( sprite, &x, &y );
			
			sprite->x = worldToScreenX( x );
			sprite->y = worldToScreenY( y );
				
			updateSpriteAttributes( sprite );
		}
		else
		{
			// if not, get them the fuck off the screen, ya moron!
			sprite->x = SCREEN_WIDTH;
			sprite->y = SCREEN_HEIGHT;
			
			//updateSpriteAttributes( sprite );
		}
	}
}

#endif
